#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>
#include <cassert>
#include <cstring>
#include <cerrno>
#include "Sock.hpp"
#include "Log.hpp"
#include "Err.hpp"
#include "Epoller.hpp"

namespace Yohifo
{
    static const std::string gip = "127.0.0.1";
    static const uint16_t gport = 8888;
    static const uint16_t gnum = 64;
    class Connection;
    
    using func_t = function<std::string(std::string)>;
    using callback_t = function<void(Connection*)>;
    
    enum
    {
        SIZE = 1024
    };

    class Connection
    {
    public:
        Connection(const int &fd, const std::string &IP, const uint16_t &Port)
            : fd_(fd), clientIP_(IP), clientPort_(Port)
        {}

        void Register(const callback_t &recv, const callback_t &send, const callback_t &except)
        {
            //给每一个 fd 都注册对应的方法
            recv_ = recv;
            send_ = send;
            except_ = except;
        }

    public:
        int fd_;
        std::string inbuff_;
        std::string outbuff_;

        // 新增成员
        std::string clientIP_;
        uint16_t clientPort_;

        //新增回调函数
        callback_t recv_;
        callback_t send_;
        callback_t except_;
    };

    class EpollServer
    {
    public:
        EpollServer(const func_t &func, uint16_t port = gport)
            : port_(port), func_(func)
        {
        }

        ~EpollServer()
        {
            // 释放哈希表中的空间
            for (auto e : connections_)
                delete e.second;

            listen_sock_.Close();
            epoller_.Close();
        }

        void InitServer()
        {
            // 初始化TCP服务器老三样
            listen_sock_.Socket();
            listen_sock_.Bind(port_);
            listen_sock_.Listen();
            epoller_.Create(gnum);

            AddConnection(listen_sock_.getFd(), READ);
        }

        //事件派发器
        void Dispatcher()
        {
            // int timeout = 1000;
            // int timeout = 0;
            int timeout = -1;

            while (true)
            {
                LoopOnce(timeout);
            }
        }

        void LoopOnce(int timeout)
        {
            int n = epoller_.Wait(revs_, gnum, timeout);
            for (int i = 0; i < n; i++)
            {
                int fd = revs_[i].data.fd;
                uint32_t event = revs_[i].events;

                // 判断事件类型
                if((event & READ)) connections_[fd]->recv_(connections_[fd]);
                if((event & WRITE)) connections_[fd]->send_(connections_[fd]);
                if((event & ERROR)) connections_[fd]->except_(connections_[fd]);
            }
        }

        void AddConnection(const int &fd, const uint32_t &events, const std::string &IP = gip, const uint32_t &Port = gport)
        {
            // 添加新的fd及事件进入 epoll
            bool ret = epoller_.Add(fd, READ);
            if (ret == false)
            {
                logMessage(Warning, "epoll_ctr(Add) fail %d %s", errno, strerror(errno));
                close(fd);
            }

            // 注册新的映射关系
            Connection *ct = new Connection(fd, IP, Port);

            //根据fd及事件注册不同的方法
            if(fd == listen_sock_.getFd()) ct->Register(std::bind(&Yohifo::EpollServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
            else ct->Register(std::bind(&Yohifo::EpollServer::Recver, this, std::placeholders::_1),
                              std::bind(&Yohifo::EpollServer::Sender, this, std::placeholders::_1),
                              std::bind(&Yohifo::EpollServer::Excepter, this, std::placeholders::_1));

            connections_.insert(make_pair(fd, ct));

            logMessage(Debug, "登记了一个新的链接信息 fd:%d IP:%s Port:%d", ct->fd_, ct->clientIP_.c_str(), ct->clientPort_);
        }

        void Accepter(Connection *conn)
        {
            (void)conn;

            // 获取新的连接
            std::string clientIP;
            uint16_t clientPort;
            int sock = listen_sock_.Accept(&clientIP, &clientPort);
            if (sock == -1)
                return;
            logMessage(Info, "fd:%d IP:%s Port:%d 连接成功", conn->fd_, clientIP.c_str(), clientPort);

            AddConnection(sock, READ, clientIP, clientPort);
        }

        void Recver(Connection *conn)
        {
            logMessage(Debug, "Recver fd:%d IP:%s Port:%d", conn->fd_, conn->clientIP_.c_str(), conn->clientPort_);
        }

        void Sender(Connection *conn)
        {
            logMessage(Debug, "Sender fd:%d IP:%s Port:%d", conn->fd_, conn->clientIP_.c_str(), conn->clientPort_);
        }

        void Excepter(Connection *conn)
        {
            logMessage(Debug, "Excepter fd:%d IP:%s Port:%d", conn->fd_, conn->clientIP_.c_str(), conn->clientPort_);
        }

    private:
        uint16_t port_;
        Sock listen_sock_;
        Epoller epoller_;
        struct epoll_event revs_[gnum];
        func_t func_;
        unordered_map<int, Connection *> connections_; // 为每个已记录的 fd 开辟对应的缓冲区
    };
}